﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Dunnice.Utility
{
    /// <summary>
    /// 并发线程控制类
    /// </summary>
    public class SimultaneousDelegateControl<T> where T : class
    {
        public delegate void SimultaneousDelegate(T t);

        private int _maxThreadCount;
        private SimultaneousDelegate _targetDelegate;
        private Queue<T> _queueNeedProcessData;
        private object _asynObj = new object();
        private bool _started = false;
        private AutoResetEvent _resetEvent;
        private string _controlName;

        public SimultaneousDelegateControl(int maxThreadCount, List<T> needProcessData, SimultaneousDelegate targetDelegate, string name)
        {
            //TODO 参数判断.

            this._maxThreadCount = maxThreadCount;
            this._targetDelegate = targetDelegate;
            this._queueNeedProcessData = new Queue<T>();

            foreach (var t in needProcessData)
            {
                this._queueNeedProcessData.Enqueue(t);
            }

            this._controlName = name;
        }

        /// <summary>
        /// 全部数据处理完毕.
        /// </summary>
        public event EventHandler<EventArgs> HandleComplated;

        /// <summary>
        /// 触发<see cref="HandleComplated"/>事件.
        /// </summary>
        protected void OnHandleComplated()
        {
            // 设置信号
            this._resetEvent.Set();

            // 触发事件
            EventHandler<EventArgs> temp = this.HandleComplated;

            if (temp != null)
            {
                temp(this, null);
            }
        }

        /// <summary>
        /// 开始处理
        /// </summary>
        public void Start()
        {
            lock (this._asynObj)
            {
                if (this._started)
                    return;

                this._started = true;
                this._resetEvent = new AutoResetEvent(false);

                for (int i = 0; i < this._maxThreadCount; i++)
                {
                    if (this._queueNeedProcessData.Count == 0)
                        break;

                    T info = this._queueNeedProcessData.Dequeue();
                    this._targetDelegate.BeginInvoke(info, new AsyncCallback(AsyncCallbackMethod), null);

                }
            }
        }

        /// <summary>
        /// 等待所有数据处理完毕.
        /// </summary>
        public void WaitToHandleComplated()
        {
            if (!this._started)
                throw new NotSupportedException("You should call this method after call Start() and before call Stop().");

            _resetEvent.WaitOne();
            _resetEvent.Reset();
        }

        /// <summary>
        /// 停止后继的数据处理.
        /// </summary>
        public void Stop()
        {
            this._started = false;
            this._resetEvent.Set();
            this._resetEvent = null;
        }

        /// <summary>
        /// 单个异步处理完毕的回调, 启动下一个回调.
        /// </summary>
        /// <param name="ir"></param>
        protected void AsyncCallbackMethod(IAsyncResult ir)
        {
            try
            {
                //TODO 异常的暴露以后再处理(异步的异常会在EndInvoke的时候才触发, 所以需要在这里处理,通知外部, 出现了异常)
                this._targetDelegate.EndInvoke(ir);
            }
            catch { }

            if (!this._started)
                return;

            lock (this._asynObj)
            {
                if (this._queueNeedProcessData.Count > 0)
                {
                    T info = this._queueNeedProcessData.Dequeue();
                    //TODO 是否会使用新线程,效率问题.
                    this._targetDelegate.BeginInvoke(info, new AsyncCallback(AsyncCallbackMethod), null);
                }
                else
                {
                    OnHandleComplated();
                }
            }
        }
    }
}